#include "HistoryDigest.hpp"

using namespace BFT::messages;

HistoryDigest::HistoryDigest(boost::shared_ptr<HistoryDigest> _history, 
			     boost::shared_ptr<CommandBatch> _batch,
			     boost::shared_ptr<NonDeterminism> _nondet,
			     boost::shared_ptr<Digest> _digest)
{
	int temp_hd_size = _history.get()->getSize();
	boost::shared_ptr<char> temp_hd_bytes = _history.get()->getBytes();
	
	int temp_commands_size;
	boost::shared_ptr<char> temp_commands_bytes  = _batch.get()->getBytes(temp_commands_size);
	
	int temp_nondet_size = _nondet.get()->getSize();
	boost::shared_ptr<char> temp_nondet_bytes = _nondet.get()->getBytes();
	
	int temp_digest_size = _digest.get()->getSize();
	boost::shared_ptr<char> temp_digest_bytes = _digest.get()->getBytes();
	
	int temp_combined_size = temp_hd_size + temp_commands_size + temp_nondet_size + temp_digest_size;
	
	boost::shared_ptr<char> temp_combined_bytes = combineArrays( temp_hd_bytes,	 temp_hd_size,
								    temp_commands_bytes, temp_commands_size,
								    temp_nondet_bytes,	 temp_nondet_size,
								    temp_digest_bytes,	 temp_digest_size );
								  
	Digest::Digest(temp_combined_bytes, temp_combined_size);
}

HistoryDigest::HistoryDigest(boost::shared_ptr<HistoryDigest> _history, 
			     boost::shared_ptr<CommandBatch> _batch,
			     boost::shared_ptr<NonDeterminism> _nondet)
{
	int temp_hd_size = _history.get()->getSize();
	boost::shared_ptr<char> temp_hd_bytes = _history.get()->getBytes();
	
	int temp_commands_size;
	boost::shared_ptr<char> temp_commands_bytes  = _batch.get()->getBytes(temp_commands_size);
	
	int temp_nondet_size = _nondet.get()->getSize();
	boost::shared_ptr<char> temp_nondet_bytes = _nondet.get()->getBytes();
	
	int temp_combined_size = temp_hd_size + temp_commands_size + temp_nondet_size;
	
	boost::shared_ptr<char> temp_combined_bytes = combineArrays( temp_hd_bytes,	 temp_hd_size,
								    temp_commands_bytes, temp_commands_size,
								    temp_nondet_bytes,	 temp_nondet_size);
								  
	Digest::Digest(temp_combined_bytes, temp_combined_size);
}

HistoryDigest::HistoryDigest(boost::shared_ptr<char>_bytes, int _bytes_size)
	: Digest::Digest(_bytes,_bytes_size)
{
}

HistoryDigest::HistoryDigest() {}

boost::shared_ptr<HistoryDigest> HistoryDigest::fromBytes( boost::shared_ptr<char> _bytes, int _bytes_size)
{
	boost::shared_ptr<HistoryDigest> hd (new HistoryDigest());
	
	hd.get()->bytes.reset( (char*)malloc(_bytes_size),free );
	memcpy(  (void*)(hd.get()->bytes.get()), (const void*)(_bytes.get()) , _bytes_size );	
	return hd;
}

boost::shared_ptr<char> HistoryDigest::combineArrays(boost::shared_ptr<char> _array1, int _array1_size,
		     			             boost::shared_ptr<char> _array2, int _array2_size,
					   	     boost::shared_ptr<char> _array3, int _array3_size,
						     boost::shared_ptr<char> _array4, int _array4_size)
{
	boost::shared_ptr<char> combined ( (char*)malloc(_array1_size + _array2_size + _array3_size + _array4_size), free );
	int offset = 0;
	
	memcpy( (void*)(combined.get()), (const void *)(_array1.get()) , _array1_size);
	offset += _array1_size;
	
	memcpy( (void*)(combined.get()+offset), (const void *)(_array2.get()) , _array2_size);
	offset += _array2_size;
	
	memcpy( (void*)(combined.get()+offset), (const void *)(_array3.get()) , _array3_size);
	offset += _array3_size;
	
	memcpy( (void*)(combined.get()+offset), (const void *)(_array4.get()) , _array4_size);

	return combined;
}						

boost::shared_ptr<char> HistoryDigest::combineArrays(boost::shared_ptr<char> _array1, int _array1_size,
		     			             boost::shared_ptr<char> _array2, int _array2_size,
					   	     boost::shared_ptr<char> _array3, int _array3_size)
{
	boost::shared_ptr<char> combined ( (char*)malloc(_array1_size + _array2_size + _array3_size) , free );
	int offset = 0;
	
	memcpy( (void*)(combined.get()), (const void *)(_array1.get()) , _array1_size);
	offset += _array1_size;
	
	memcpy( (void*)(combined.get()+offset), (const void *)(_array2.get()) , _array2_size);
	offset += _array2_size;
	
	memcpy( (void*)(combined.get()+offset), (const void *)(_array3.get()) , _array3_size);

	return combined;
}						  
